package weka.classifiers.trees;

import grex.Options;

import java.io.Serializable;
import java.util.Enumeration;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import weka.classifiers.AbstractClassifier;
import weka.core.AdditionalMeasureProducer;
import weka.core.Capabilities;
import weka.core.Drawable;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Option;
import weka.core.OptionHandler;
import weka.core.RevisionUtils;
import weka.core.SelectedTag;
import weka.core.Summarizable;
import weka.core.Tag;
import weka.core.Utils;
import weka.core.Capabilities.Capability;
import wekaGrexBridge.WekaWrapper;

/**
 * <p>Title: Weka</p>
 *
 * <p>Description: weka.classifiers.trees.grex </p>
 *
 * <p>Copyright: Copyright (c) 2006</p>
 *
 * <p>Company: University of Borås</p>
 *
 * @author Tuve Löfström & Rikard König
 * @version 1.0
 */


public class Grex extends AbstractClassifier implements OptionHandler, Serializable, Summarizable, AdditionalMeasureProducer {

	private static final long serialVersionUID = 3814262435771428589L;
	public Options opt;
    protected WekaWrapper model;
    protected boolean classificationTask = true;
    public static final Tag[] TAGS_crt = {
        new Tag(0, "Ramped-Half-and-Half"),
        new Tag(1, "Grow"),
        new Tag(2, "Variable")
    };
    public static Tag[] TAGS_BNF;
    public static Tag[] TAGS_Fitness;
    public static Tag[] TAGS_Start = {
        new Tag(0, "Start as normal"),
        new Tag(1, "Use Tree Injection"),
        new Tag(2, "Start from Random Forest"),
        new Tag(3, "Run in experiment mode - for development purposes only")
    };
    public int m_crt = 0, m_BNF = 0, m_Fitness = 0, m_start = 0;
//------------------------------------------------------------

    public Grex() throws Exception {
        String[] tmp = WekaWrapper.getDiredctoryBNFs();
        opt = new grex.Options();
        TAGS_BNF = new Tag[tmp.length];
        for (int i = 0; i < tmp.length; i++) {
            TAGS_BNF[i] = new Tag(i, tmp[i]);
            if (tmp[i].equalsIgnoreCase(opt.getBNF_FILE() + ".txt"))
                m_BNF = i;
        }
        Grex.updateTAGS_Fitness();
        //.setNR_OF_FOLDS(1);
        //m_BNF = 10; //If
        for (int i = 0; i < TAGS_Fitness.length; i++) {
            if (TAGS_Fitness[i].getReadable().equalsIgnoreCase(opt.getFITNESS_FUNCTION())) {
                m_Fitness = i;
                break;
            }
        }
        setBNF_File(new SelectedTag(m_BNF, TAGS_BNF));
        setFitness(new SelectedTag(m_Fitness, TAGS_Fitness));
    }

    public Grex(String bnf) throws Exception {
        this();
        for (int i = 0; i < TAGS_BNF.length; i++) {
            if (TAGS_BNF[i].getReadable().toLowerCase().contains(bnf.toLowerCase())) {
                m_BNF = i;
                setBNF_File(new SelectedTag(m_BNF, TAGS_BNF));
                return;
            }
        }
    }

    public WekaWrapper getModel() {
        return model;
    }

    public void setModel(WekaWrapper m) {
        model = m;
    }

    public static Tag[] updateTAGS_Fitness() {
        String[] tmp = WekaWrapper.getFitnessFunctions();
        TAGS_Fitness = new Tag[tmp.length];
        for (int i = 0; i < tmp.length; i++) {
            TAGS_Fitness[i] = new Tag(i, tmp[i]);
        }
        return TAGS_Fitness;
    }

    /**
     * Returns a string describing the classifier.
     * @return a description suitable for the GUI.
     * @todo skriv om instruktionerna...
     * till�ts saknade v�rden?
     * se vad? n�gon artikel kanske
     */
    public String globalInfo() {

        return "Class for constructing various kinds of models with a GP " + "algorithm. For more " + "information see: \n\n" + "... ";
    }

    /**
     * Returns default capabilities of the classifier.
     *
     * @return      the capabilities of this classifier
     */
    public Capabilities getCapabilities() {
        Capabilities result = new Capabilities(this);

        // attributes
        result.enable(Capability.NOMINAL_ATTRIBUTES);
        result.enable(Capability.NUMERIC_ATTRIBUTES);
        result.enable(Capability.DATE_ATTRIBUTES);
        result.enable(Capability.MISSING_VALUES);

        // class
        result.enable(Capability.NOMINAL_CLASS);
        result.enable(Capability.MISSING_CLASS_VALUES);

        return result;
    }

    /**
     * Generates a classifier.
     *
     * @param data set of instances serving as training data
     * @throws Exception if the classifier has not been generated
     *   successfully
     */
    public void buildClassifier(Instances data) throws Exception {
        Instances newData = new Instances(data); //copy data
        model = new WekaWrapper(newData, opt);
        model.buildWraper();
    }

    /**
     * Classifies a given test instance using the decision tree.
     *
     * @param instance the instance to be classified
     * @return the classification
     */
    public double classifyInstance(Instance instance) throws Exception {
        return model.classifyInstance(instance);
    }

    /**
     * Computes class distribution for instance using decision tree.
     *
     * @param instance the instance for which distribution is to be computed
     * @return the class distribution for the given instance
     * @todo implementera denna...
     */
    public double[] distributionForInstance(Instance instance) throws Exception {
        return model.distributionForInstance(instance);
    }

    /**
     * Returns the revision string.
     * 
     * @return		the revision
     */
    public String getRevision() {
        return RevisionUtils.extract("$Revision: 1.0 $");
    }

    /**
     * Returns an enumeration describing the available options.
     *
     * @return an enumeration of all the available options.
     */
    @SuppressWarnings("unchecked")
	public Enumeration listOptions() {

        Vector<Option> newVector = new Vector<Option>();

        newVector.addElement(new Option(
                "\tIf set, grex uses the given file name as bnf file.\n" + "\t[file name] (autogenerated)",
                "bnf", 1,
                "-bnf < name of BNF file, [file name] (autogenerated) >"));
        newVector.addElement(new Option(
                "\tIf set, grex is run the given number of generatiosns.\n" + "\t[>0]",
                "gen", 1, "-gen < number of generations, [>0] (1000) >"));
        newVector.addElement(new Option(
                "\tIf set, grex creates a population of the given size.\n" + "\t[>0]",
                "pop", 1, "-pop, < population size, [>0] (500) >"));
        newVector.addElement(new Option(
                "\tIf set, grex uses the given fraction as cross over \n" + "\trate. [0-1] (0.8)",
                "cro", 1, "-cro < crossover rate, [0-1] (0.8) >"));
        newVector.addElement(new Option(
                "\tIf set, grex uses the given fraction as mutaion rate.\n" + "\t[0-1]",
                "mut", 1, "-mut < mutation rate, [0-1] (0.0001) >"));
        newVector.addElement(new Option(
                "\tIf set, grex uses the given number as max creation depth.\n" + "\t[>0]",
                "crd", 1, "-crd < creation depth, [>0] (6) >"));
        newVector.addElement(new Option(
                "\tIf set, grex uses the given number as length factor.\n" + "\t[>0]",
                "len", 1, "-len < length factor, [>0] (0.01) >"));
        newVector.addElement(new Option(
                "\tIf set, grex uses the simplification. (false)",
                "sim", 0, "-sim"));
        newVector.addElement(new Option(
                "\tIf set, grex uses the given algorithm as creation\n" + "\talgorithm. [RAMPED_H&H = 0, GROW = 1, VARIABLE = 2] (0)",
                "crt", 1,
                "-crt < creation function, [RAMPED_H&H = 0, GROW = 1, VARIABLE = 2] (0) >"));
        newVector.addElement(new Option(
                "\tGrex uses the given alternative as the inital population.",
                "strt", 1,
                "-strt < initial population >"));
        newVector.addElement(new Option(
                "\tIf set, grex uses elitism, i.e. the best gene survives\n" + "\tto the next generation. (true)",
                "eli", 0, "-eli"));
        newVector.addElement(new Option(
                "\tIf set, grex uses stops if no change in fitness for the\n" + "\tgiven number of generations. [0>] (100)",
                "per", 1, "-per < number of generations without changes to run before stopping, [0>] (100) >"));
        newVector.addElement(new Option(
                "\tIf set, grex is run bat number of batches. The best GP in the winning batch is returned \n" + "\t[>0] (1)",
                "bat", 1, "-bat < number of batches, [>0] (1) >"));
        newVector.addElement(new Option(
                "\t"+tournamentSizeTipText() +" \n" + "\t[>=0] (4)",
                "tos", 1, "-tos < number of tournament members, [>=0] (4) >"));
        newVector.addElement(new Option(
                "\tParameter1\n" + "\t[>0]",
                "len", 1, "-p1 < Paramter1, [>0] (97.8) >"));
        newVector.addElement(new Option(
                "\tParameter2\n" + "\t[>0]",
                "len", 1, "-p2 < Paramter2, [>0] (97.8) >"));
        newVector.addElement(new Option(
                "\tParameter3\n" + "\t[>0]",
                "len", 1, "-p3 < Paramter3, [>0] (97.8) >"));
        newVector.addElement(new Option(
                "\tParameter4\n" + "\t[>0]",
                "len", 1, "-p4 < Paramter4, [>0] (97.8) >"));
        Enumeration<Option> enu = super.listOptions();
        while (enu.hasMoreElements()) {
            newVector.addElement(enu.nextElement());
        }

        return newVector.elements();
    }

    /**
     * Parses a given list of options. Valid options are:<p>
     *
     * -D  <br>
     * If set, classifier is run in debug mode and
     * may output additional info to the console.<p>
     *
     * @param options the list of options as an array of strings
     * @exception Exception if an option is not supported
     */
    public void setOptions(String[] options) throws Exception {
        String tmp = Utils.getOption("bnf", options);
        if (tmp.length() != 0) {
            setBNF_File(
                    new SelectedTag(Integer.parseInt(tmp), TAGS_BNF));
        } else {
            setBNF_File(
                    new SelectedTag(m_BNF, TAGS_BNF));
        }

        tmp = Utils.getOption("fit", options);
        if (tmp.length() != 0) {
            setFitness(
                    new SelectedTag(Integer.parseInt(tmp), Grex.updateTAGS_Fitness()));
        } else {
            setFitness(
                    new SelectedTag(m_Fitness, Grex.updateTAGS_Fitness()));
        }

        tmp = Utils.getOption("gen", options);
        if (tmp.length() != 0) {
            setGenerations(Integer.parseInt(tmp));
        }

        tmp = Utils.getOption("pop", options);
        if (tmp.length() != 0) {
            setPopulationSize(Integer.parseInt(tmp));
        }

        tmp = Utils.getOption("cro", options);
        if (tmp.length() != 0) {
            setCrossoverProbability(Double.parseDouble(tmp));
        }

        tmp = Utils.getOption("mut", options);
        if (tmp.length() != 0) {
            setMutationProbability(Double.parseDouble(tmp));
        }

        tmp = Utils.getOption("crd", options);
        if (tmp.length() != 0) {
            setCreationDepth(Integer.parseInt(tmp));
        }

        tmp = Utils.getOption("len", options);
        if (tmp.length() != 0) {
            setLengthFactor(Double.parseDouble(tmp));
        }

        tmp = Utils.getOption("bat", options);
        if (tmp.length() != 0) {
            setNumberOfBatches(Integer.parseInt(tmp));
        }

        setSimplify(Utils.getFlag("sim", options));

        tmp = Utils.getOption("crt", options);
        if (tmp.length() != 0) {
            setCreationType(
                    new SelectedTag(Integer.parseInt(tmp), TAGS_crt));
        } else {
            setCreationType(
                    new SelectedTag(m_crt, TAGS_crt));
        }

        tmp = Utils.getOption("strt", options);
        if (tmp.length() != 0) {
            setInitialPopulation(
                    new SelectedTag(Integer.parseInt(tmp), TAGS_Start));
        } else {
            setInitialPopulation(
                    new SelectedTag(m_start, TAGS_Start));
        }

        setElitism(Utils.getFlag("eli", options));

        tmp = Utils.getOption("per", options);
        if (tmp.length() != 0) {
            setStopWithoutImprovement(Integer.parseInt(tmp));
        }

        tmp = Utils.getOption("tos", options);
        if (tmp.length() != 0) {
            setTournamentSize(Integer.parseInt(tmp));
        }

        tmp = Utils.getOption("p1", options);
        if (tmp.length() != 0) {
            setParamter1(Double.parseDouble(tmp));
        }
        tmp = Utils.getOption("p2", options);
        if (tmp.length() != 0) {
            setParamter2(Double.parseDouble(tmp));
        }
        tmp = Utils.getOption("p3", options);
        if (tmp.length() != 0) {
            setParamter3(Double.parseDouble(tmp));
        }
        tmp = Utils.getOption("p4", options);
        if (tmp.length() != 0) {
            setParamter4(Double.parseDouble(tmp));
        }
    }

    /**
     * Gets the current settings of the Classifier.
     *
     * @return an array of strings suitable for passing to setOptions
     */
    public String[] getOptions() {

		Vector<String> result = new Vector<String>();
        String[] options;

        result.add("-bnf");
        result.add("" + getBNF_File());
        result.add("-fit");
        result.add("" + getFitness());
        result.add("-gen");
        result.add("" + getGenerations());
        result.add("-pop");
        result.add("" + getPopulationSize());
        result.add("-cro");
        result.add("" + getCrossoverProbability());
        result.add("-mut");
        result.add("" + getMutationProbability());
        result.add("-crd");
        result.add("" + getCreationDepth());
        result.add("-len");
        result.add("" + getLengthFactor());
        result.add("-bat");
        result.add("" + getNumberOfBatches());
        if (getSimplify()) {
        	result.add("-sim");
        }
        result.add("-crt");
        result.add("" + getCreationType());
        result.add("-strt");
        result.add("" + getInitialPopulation());
        if (getElitism()) {
            result.add("-eli");
        }
        result.add("-per");
        result.add("" + getStopWithoutImprovement());
        result.add("-tos");
        result.add("" + getTournamentSize());
        result.add("-p1");
        result.add("" + getParamter1());
        result.add("-p2");
        result.add("" + getParamter2());
        result.add("-p3");
        result.add("" + getParamter3());
        result.add("-p4");
        result.add("" + getParamter4());
        options = super.getOptions();
		for (int i = 0; i < options.length; i++) {
			result.add(options[i]);
		}

		String[] array = new String[result.size()];
		for (int i = 0; i < result.size(); i++)
			array[i] = result.elementAt(i).toString();

		return array; // (String[]) result.toArray(new String[result.size()]);
    }

    public void useProbabilities() {
        for (int i = 0; i < TAGS_BNF.length; i++) {
            if (TAGS_BNF[i].getReadable().equalsIgnoreCase("AA If Probs.txt")) {
                m_BNF = i;
                break;
            }
        }
        this.setBNF_File(new SelectedTag(m_BNF, TAGS_BNF));
        for (int i = 0; i < TAGS_Fitness.length; i++) {
            if (TAGS_Fitness[i].getReadable().equalsIgnoreCase("probfitness")) {
                m_Fitness = i;
                break;
            }
        }
        this.setFitness(new SelectedTag(0, TAGS_Fitness));
    }

    /**
     * Prints the decision tree using the private toString method from below.
     *
     * @return a textual description of the classifier
     */
    public String toString() {
        if (model == null) {
            return "No grex classifier created yet!";
        }
        String result = "";
        if (opt.isSIMPLIFICATION()) {
            result += "Simplified GREX model:\n----------------------\n\n";
        } else {
            result += "GREX model:\n-----------\n\n";
        }
        result += model.toString() + "\n";
        result += "Tree size: " + model.getTreeSize() + "\n";
        result += "Num Leaves: " + model.getNumLeaves();
        return result;
    }

    /**
     *  Returns the type of graph this classifier
     *  represents.
     *  @return Drawable.TREE
     */
    public int graphType() {
        return Drawable.TREE;
    }

    /**
     * Returns graph describing the tree.
     *
     * @exception Exception if graph can't be computed
     */
    public String graph() throws Exception {

        return "";
    }

    /**
     * Returns tree in prefix order.
     *
     * @exception Exception if something goes wrong
     */
    public String prefix() throws Exception {

        return "";
    }

    /**
     * Returns tree as an if-then statement.
     *
     * @return the tree as a Java if-then type statement
     * @exception Exception if something goes wrong
     */
    public String toSource(String className) throws Exception {
        return "";
        /*StringBuffer [] source = m_root.toSource(className);
        return
        "class " + className + " {\n\n"
        +"  public static double classify(Object [] i)\n"
        +"    throws Exception {\n\n"
        +"    double p = Double.NaN;\n"
        + source[0]  // Assignment code
        +"    return p;\n"
        +"  }\n"
        + source[1]  // Support code
        +"}\n";*/
    }

    /**
     * Returns a superconcise version of the model
     */
    public String toSummaryString() {
        return "Compact tree respresentation: " + model.toString() + "\n";
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String crossoverProbabilityTipText() {
        return "The crossover probability used.";
    }

    /**
     * Get the value of cro.
     *
     * @return Value of cro.
     */
    public double getCrossoverProbability() {

        return opt.getCROSSOVER_PROBABILITY();
    }

    /**
     * Set the value of cro.
     *
     * @param crossoverProbability Value to assign to cro.
     */
    public void setCrossoverProbability(double crossoverProbability) {

        opt.setCROSSOVER_PROBABILITY(crossoverProbability);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String mutationProbabilityTipText() {
        return "The mutation probability used.";
    }

    /**
     * Get the value of mut.
     *
     * @return Value of mut.
     */
    public double getMutationProbability() {

        return opt.getMUTATION_PROBABILITY();
    }

    /**
     * Set the value of mut.
     *
     * @param mutationProbability Value to assign to mut.
     */
    public void setMutationProbability(double mutationProbability) {

        opt.setMUTATION_PROBABILITY(mutationProbability);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String lengthFactorTipText() {
        return "The length factor to be used as a means of controlling the complexity of the classifier.";
    }

    /**
     * Get the value of len.
     *
     * @return Value of len.
     */
    public double getLengthFactor() {

        return opt.getPUNISHMENT_FOR_LENGTH();
    }

    public double getParamter1(){
        return opt.getPARAMETER_1();
    }
    public double getParamter2(){
        return opt.getPARAMETER_2();
    }
    public double getParamter3(){
        return opt.getPARAMETER_3();
    }
    public double getParamter4(){
        return opt.getPARAMETER_4();
    }
    /**
     * Set the value of len.
     *
     * @param lengthFactor Value to assign to len.
     */
    public void setLengthFactor(double lengthFactor) {

        opt.setPUNISHMENT_FOR_LENGTH(lengthFactor);
    }

    //Parameter for various experiments (used for hacks and quick fixes :-)
    public void setParamter1(double parameter1) {
        opt.setPARAMETER_1(parameter1);
    }
    public void setParamter2(double parameter2) {
        opt.setPARAMETER_2(parameter2);
    }
    public void setParamter3(double parameter3) {
        opt.setPARAMETER_3(parameter3);
    }
    public void setParamter4(double parameter4) {
        opt.setPARAMETER_4(parameter4);
    }



    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String BNF_FileTipText() {
        return "The BNF file to use.";
    }

    /**
     * Get the value of
     *
     * @return Value of Settings.
     */
    public SelectedTag getBNF_File() {
        for (int i = 0; i < TAGS_BNF.length; i++) {
            if (TAGS_BNF[i].getReadable().equals(opt.getBNF_FILE())) {
                m_BNF = i;
            }
        }
        return new SelectedTag(m_BNF, TAGS_BNF);
    }

    /**
     * Set the value of Settings.
     *
     * @param bnfFile Value to assign to Settings.
     */
    public void setBNF_File(SelectedTag value) {
        if (value.getTags() == TAGS_BNF) {
            opt.setBNF_FILE(value.getSelectedTag().getReadable());
            m_BNF = value.getSelectedTag().getID();
        }
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String FitnessTipText() {
        return "The Fitness function to use.";
    }

    /**
     * Get the value of
     *
     * @return Value of Settings.
     */
    public SelectedTag getFitness() {
        for (int i = 0; i < Grex.updateTAGS_Fitness().length; i++) {
            if (TAGS_Fitness[i].getReadable().equals(opt.getFITNESS_FUNCTION())) {
                m_Fitness = i;
            }
        }
        return new SelectedTag(m_Fitness, TAGS_Fitness);
    }

    /**
     * Set the value of Settings.
     *
     * @param Fitness Value to assign to Settings.
     */
    public void setFitness(SelectedTag value) {
            opt.setFITNESS_FUNCTION(value.getSelectedTag().getReadable());
            m_Fitness = value.getSelectedTag().getID();
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String generationsTipText() {
        return "The number of generations to run.";
    }

    /**
     * Get the value of gen.
     *
     * @return Value of gen.
     */
    public int getGenerations() {

        return opt.getGENERATIONS();
    }

    /**
     * Set the value of gen.
     *
     * @param generations Value to assign to gen.
     */
    public void setGenerations(int generations) {

        opt.setGENERATIONS(generations);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String evolveRandomForestTipText() {
        return "The evolve a Random Forest.";
    }

    /**
     * Get the value of gen.
     *
     * @return Value of gen.
     */
    public boolean getEvolveRandomForest() {

        return opt.isEVOLVE_RANDOMFOREST();
    }

    /**
     * Set the value of gen.
     *
     * @param generations Value to assign to gen.
     */
    public void setEvolveRandomForest(boolean evlove_rf) {

        opt.setEVOLVE_RANDOMFOREST(evlove_rf);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String populationSizeTipText() {
        return "The size of the population.";
    }

    /**
     * Get the value of pop.
     *
     * @return Value of pop.
     */
    public int getPopulationSize() {

        return opt.getPOPULATION_SIZE();
    }

    /**
     * Set the value of pop.
     *
     * @param populationSize Value to assign to pop.
     */
    public void setPopulationSize(int populationSize) {

        opt.setPOPULATION_SIZE(populationSize);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String creationDepthTipText() {
        return "The maximum creation depth of generated genes.";
    }

    /**
     * Get the value of crd.
     *
     * @return Value of crd.
     */
    public int getCreationDepth() {

        return opt.getMAX_CREATION_DEPTH();
    }

    /**
     * Set the value of crd.
     *
     * @param creationDepth Value to assign to crd.
     */
    public void setCreationDepth(int creationDepth) {

        opt.setMAX_CREATION_DEPTH(creationDepth);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String creationTypeTipText() {
        return "The creation strategy to use. [RAMPED_H&H = 0, GROW = 1, VARIABLE = 2]";
    }

    /**
     * Get the value of crt.
     *
     * @return Value of crt.
     */
    public SelectedTag getCreationType() {

        return new SelectedTag(opt.getCREATION_TYPE(), TAGS_crt);
    }

    /**
     * Set the value of crt.
     *
     * @param creationType Value to assign to crt.
     */
    public void setCreationType(SelectedTag value) {
        if (value.getTags() == TAGS_crt) {
            m_crt = value.getSelectedTag().getID();
        }
        opt.setCREATION_TYPE(m_crt);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String initialPopulationTipText() {
        return "Alternative initialization strategies for the initial population";
    }

    /**
     * Get the value of crt.
     *
     * @return Value of crt.
     */
    public SelectedTag getInitialPopulation() {

        return new SelectedTag(m_start, TAGS_Start);
    }

    /**
     * Set the value of crt.
     *
     * @param creationType Value to assign to crt.
     */
    public void setInitialPopulation(SelectedTag value) {
        if (value.getTags() == TAGS_Start) {
            m_start = value.getSelectedTag().getID();
        }
        switch (m_start) {
            case 0:
                opt.setUSE_GP_INJECTION(false);
                opt.setSTART_FROM_RANDOMFOREST(false);
                opt.setRUN_EXPERIMENT_MODE(false);
                break;
            case 1:
                opt.setUSE_GP_INJECTION(true);
                opt.setSTART_FROM_RANDOMFOREST(false);
                opt.setRUN_EXPERIMENT_MODE(false);
                break;
            case 2:
                opt.setUSE_GP_INJECTION(false);
                opt.setSTART_FROM_RANDOMFOREST(true);
                opt.setRUN_EXPERIMENT_MODE(false);
                break;
            case 3: 
                opt.setUSE_GP_INJECTION(false);
                opt.setSTART_FROM_RANDOMFOREST(false);
                opt.setRUN_EXPERIMENT_MODE(true);
                break;            	
        }
        opt.setCREATION_TYPE(m_crt);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String stopWithoutImprovementTipText() {
        return "The maximum generations to continue running without improvement. Also called percistence";
    }

    /**
     * Get the value of per.
     *
     * @return Value of per.
     */
    public int getStopWithoutImprovement() {

        return opt.getSTOP_WITHOUT_IMPROVMENT();
    }

    /**
     * Set the value of per.
     *
     * @param stopWithoutImprovement Value to assign to per.
     */
    public void setStopWithoutImprovement(int stopWithoutImprovement) {

        opt.setSTOP_WITHOUT_IMPROVMENT(stopWithoutImprovement);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String numberOfBatchesTipText() {
        return "The number of batches to run";
    }

    /**
     * Get the value of bat.
     *
     * @return Value of bat.
     */
    public int getNumberOfBatches() {

        return opt.getBATCH_SIZE();
    }

    /**
     * Set the value of bat.
     *
     * @param numberOfBatches Value to assign to bat.
     */
    public void setNumberOfBatches(int numberOfBatches) {

        opt.setBATCH_SIZE(numberOfBatches);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String tournamentSizeTipText() {
        return "The number of tournament members. If set to 0, Roulette wheels selection is used instead.";
    }

    /**
     * Get the value of bat.
     *
     * @return Value of bat.
     */
    public int getTournamentSize() {

        return opt.getNR_OF_TOURNAMNET_MEMBERS();
    }

    /**
     * Set the value of bat.
     *
     * @param numberOfBatches Value to assign to bat.
     */
    public void setTournamentSize(int NR_OF_TOURNAMNET_MEMBERS) {

        opt.setNR_OF_TOURNAMNET_MEMBERS(NR_OF_TOURNAMNET_MEMBERS);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String simplifyTipText() {
        return "Try to simplify the final rule?";
    }

    /**
     * Get the value of sim.
     *
     * @return Value of sim.
     */
    public boolean getSimplify() {

        return opt.isSIMPLIFICATION();
    }

    /**
     * Set the value of sim.
     *
     * @param simplify Value to assign to sim.
     */
    public void setSimplify(boolean simplify) {

        opt.setSIMPLIFICATION(simplify);
    }

    /**
     * Returns the tip text for this property
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String elitismTipText() {
        return "Always let the best individual survive to the next generation?";
    }

    /**
     * Get the value of eli.
     *
     * @return Value of eli.
     */
    public boolean getElitism() {

        return opt.isELITISM();
    }

    /**
     * Set the value of eli.
     *
     * @param elitism Value to assign to eli.
     */
    public void setElitism(boolean elitism) {

        opt.setELITISM(elitism);
    }

    public void setFirstANN(int n) {
        opt.setFIRST_ANN(n);
    }

    /**
     * Main method.
     *
     * @param args the options for the classifier
     */
    public static void main(String[] args) {
        try {
            runClassifier(new Grex(), args);
        } catch (Exception ex) {
            Logger.getLogger(Grex.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @SuppressWarnings("unchecked")
	public Enumeration enumerateMeasures() {
        Vector newVector = new Vector();
        newVector.addElement("measureTreeSize");
        newVector.addElement("measureNumLeaves");
        return newVector.elements();
    }

    public double getMeasure(String additionalMeasureName) {
        if (additionalMeasureName.compareToIgnoreCase("measureTreeSize") == 0) {
            return model.getTreeSize();
        } else if (additionalMeasureName.compareToIgnoreCase("measureNumLeaves") == 0) {
            return model.getNumLeaves();
        } else {
            throw new IllegalArgumentException(additionalMeasureName + " not supported (j48)");
        }
    }
}
